using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Xml;
using WcfExtensions.ServiceModel.Channels;

namespace WcfExtensions.ServiceModel.TestClient.Scenarios.Xml
{
    internal sealed class XmlScenario
    {
        private const int MaxMessageByteSize = 52428800;
        private static readonly TimeSpan TimeOut = new TimeSpan(0, 5, 0);

        private readonly string _xmlFilePath;

        public XmlScenario(string xmlFilePath)
        {
            _xmlFilePath = xmlFilePath;
        }

        public void Run()
        {
            RunScenario(new Uri("http://localhost:999/testservice"), CreateBinding());
            //RunScenario(new Uri("net.pipe://localhost/testservice"), CreateNpBinding());
            //RunScenario(new Uri("net.tcp://localhost:99/testservice"), CreateTcpBinding());
        }

        private void RunScenario(Uri uri, Binding binding)
        {
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(_xmlFilePath);

            var msg = new XmlMessage {TimeStamp = DateTime.Now, Document = xmlDoc.DocumentElement};

            using (var host = new ServiceHost(typeof(XmlService), uri))
            {
                host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
                host.AddServiceEndpoint(typeof(IXmlService), binding, uri);
                host.Open();


                var channel = new ChannelFactory<IXmlService>(binding, new EndpointAddress(uri)).CreateChannel(new EndpointAddress(uri));

                Console.WriteLine(channel.SendMessage(msg));

                ((IClientChannel)channel).Close();

                host.Close();
            }
        }

        private static CustomBinding CreateBinding()
        {
            var element = new CompressionBindingElement
                              {
                                  Algorithm = CompressionAlgorithm.GZip,
                                  Level = CompressionLevel.Maximum
                              };

            var binding = new CustomBinding {SendTimeout = TimeOut, ReceiveTimeout = TimeOut};

            binding.Elements.Add(element);
            binding.Elements.Add(SecurityBindingElement.CreateSspiNegotiationBindingElement());

            var encoder = new TextMessageEncodingBindingElement();
            encoder.ReaderQuotas.MaxStringContentLength = MaxMessageByteSize;
            encoder.ReaderQuotas.MaxArrayLength = MaxMessageByteSize;
            encoder.ReaderQuotas.MaxBytesPerRead = MaxMessageByteSize;
            encoder.ReaderQuotas.MaxDepth = MaxMessageByteSize;
            binding.Elements.Add(encoder);

            var transport = new HttpTransportBindingElement
                                {
                                    MaxBufferSize = MaxMessageByteSize,
                                    MaxReceivedMessageSize = MaxMessageByteSize
                                };
            binding.Elements.Add(transport);
            return binding;
        }

        private static CustomBinding CreateTcpBinding()
        {
            var binding = new CustomBinding {SendTimeout = TimeOut, ReceiveTimeout = TimeOut};
            binding.Elements.Add(new CompressionBindingElement());

            var e = new BinaryMessageEncodingBindingElement();
            e.ReaderQuotas.MaxStringContentLength = MaxMessageByteSize;
            e.ReaderQuotas.MaxArrayLength = MaxMessageByteSize;
            e.ReaderQuotas.MaxBytesPerRead = MaxMessageByteSize;
            e.ReaderQuotas.MaxDepth = MaxMessageByteSize;
            binding.Elements.Add(e);

            var transport = new TcpTransportBindingElement
                                {
                                    MaxReceivedMessageSize = MaxMessageByteSize,
                                    MaxBufferSize = MaxMessageByteSize
                                };
            binding.Elements.Add(transport);
            return binding;
        }

        private static CustomBinding CreateNpBinding()
        {
            var binding = new CustomBinding { SendTimeout = TimeOut, ReceiveTimeout = TimeOut };
            binding.Elements.Add(new CompressionBindingElement());
            var e = new BinaryMessageEncodingBindingElement();
            e.ReaderQuotas.MaxStringContentLength = MaxMessageByteSize;
            e.ReaderQuotas.MaxArrayLength = MaxMessageByteSize;
            e.ReaderQuotas.MaxBytesPerRead = MaxMessageByteSize;
            e.ReaderQuotas.MaxDepth = MaxMessageByteSize;

            binding.Elements.Add(e);
            var transport = new NamedPipeTransportBindingElement
                                {
                                    MaxBufferSize = MaxMessageByteSize,
                                    MaxReceivedMessageSize = MaxMessageByteSize
                                };


            binding.Elements.Add(transport);
            return binding;
        }
    }
}